package cn.liangent.travlib;

import static cn.liangent.travlib.util.Utilities.*;
import java.io.*;
import java.util.*;
import java.util.logging.*;

public abstract class Building {
	//public abstract void demolish();
	private static final Logger logger = Logger.getLogger(Building.class.getCanonicalName());
	private final Client client;
	private final Village village;
	private final int id, newdid;
	private final User user;
	public static final Comparator<Building> COMPARE_BY_LEVEL = new Comparator<Building>() {
		public int compare(Building b1, Building b2) {
			try {
				return b1.getLevel() - b2.getLevel();
			} catch (Exception ex) {
				logger.warning("getLevel() failed in comparing<COMPARE_BY_LEVEL>, message: " + ex.getMessage());
				return 0;
			}
		}
	};

	public static enum Type {
		BUILDING_SITE,
		WOODCUTTER,	CLAY_PIT,	IRON_MINE,	CROPLAND,
		SAWMILL,	BRICKYARD,	IRON_FOUNDRY,	GRAIN_MILL,
		BAKERY,		WAREHOUSE,	GRANARY,	BLACKSMITH,
		ARMOURY,	TOURNAMENT_SQUARE, MAIN_BUILDING, RALLY_POINT,
		MARKETPLACE,	EMBASSY,	BARRACKS,	STABLE,
		WORKSHOP,	ACADEMY,	CRANNY,		TOWN_TALL,
		RESIDENCE,	PALACE,		TREASURY,	TRADE_OFFICE,
		GREAT_BARRACKS,	GREAT_STABLE,	CITY_WALL,	EARTH_WALL,
		PALISADE,	STONEMASON,	BREWERY,	TRAPPER,
		HEROS_MANSION,	GREAT_WAREHOUSE, GREAT_GRANARY,	WONDER_OF_THE_WORLD;

		public int getGid() {
			return ordinal();
		}

		// dont throw BadPageException? another? 
		public static Type forName(String name, User usr) throws BadPageException {
			Type[] types = Type.class.getEnumConstants();
			for (Type t : types) {
				// or try valueOf from standard names provided by usr?
				if (usr.getString(t.name()).equals(name)) {
					return t;
				}
			}
			throw new BadPageException("building type named " + name + " cannot be found in specific User");
		}
	}

	public Building(Village village, int id) {
		if (village == null) {
			throw new NullPointerException();
		}
		if (id < 1 || id > 40) {
			throw new IllegalArgumentException();
		}
		this.village = village;
		this.client = village.getClient();
		this.user = client.getUser();
		this.id = id;
		this.newdid = village.getNewdid();
	}
	
	public Village getVillage() {
		return village;
	}

	public int getId() {
		return id;
	}
	
	/**
	 * @return level, 0 if getType() == Type.BUILDING_SITE or a resource field
	 */
	public int getLevel() throws IOException, HttpException, AuthenticationException, BadPageException {
		int myid = getId();
		String pgsrc = getBuildingPage(myid);
		logger.info("getting level of: /build.php?id=" + myid);
		logger.fine("source:");
		logger.fine(pgsrc);
		String slevel = findNoThrow(pgsrc, "\\Q<h1><b>\\E[^ ]+\\Q " + user.getString("level")+ 
			" \\E(\\d+)\\Q</b></h1>\\E");
		if (slevel != null) {
			int level;
			try {
				level = Integer.parseInt(slevel);
			} catch (Exception ex) {
				throw new BadPageException(ex);
			}
			if (level < 0) {
				throw new BadPageException("level < 0");
			}
			return level;
		} else {
			// throw bad page exception if no this string
			// find this or level number first?
			if (!pgsrc.contains(user.getString("Construct new building"))) {
				throw new BadPageException("no type number nor 'Construct new building'");
			}
			return 0;
		}
	}
	
	/**
	 * @return null if this is a building site
	 */
	public CompleteResourceData getUpgradingCost() throws IOException, HttpException, AuthenticationException, BadPageException {
		String pgsrc = getBuildingPage();
		if (pgsrc.contains(user.getString("Construct new building"))) {
			return null;
		}
		// <img class="res" src="img/un/r/1.gif">70 | <img class="res" src="img/un/r/2.gif">90 | <img class="res" src="img/un/r/3.gif">70 | <img class="res" src="img/un/r/4.gif">20 | <img class="res" src="img/un/r/5.gif">0 |
		String slumber = find(pgsrc, "\\Q<img class=\"res\" src=\"\\E[^\"]*\\Qimg/un/r/1.gif\">\\E(\\d+)\\Q |\\E");
		String sclay = find(pgsrc, "\\Q<img class=\"res\" src=\"\\E[^\"]*\\Qimg/un/r/2.gif\">\\E(\\d+)\\Q |\\E");
		String siron = find(pgsrc, "\\Q<img class=\"res\" src=\"\\E[^\"]*\\Qimg/un/r/3.gif\">\\E(\\d+)\\Q |\\E");
		String scrop = find(pgsrc, "\\Q<img class=\"res\" src=\"\\E[^\"]*\\Qimg/un/r/4.gif\">\\E(\\d+)\\Q |\\E");
		String scc = find(pgsrc, "\\Q<img class=\"res\" src=\"\\E[^\"]*\\Qimg/un/r/5.gif\">\\E(\\d+)\\Q |\\E");
		int lumber, clay, iron, crop, cc;
		try {
			lumber = Integer.parseInt(slumber);
			clay = Integer.parseInt(sclay);
			iron = Integer.parseInt(siron);
			crop = Integer.parseInt(scrop);
			cc = Integer.parseInt(scc);
		} catch (Exception ex) {
			throw new BadPageException(ex);
		}
		if (lumber < 0 || clay < 0 || iron < 0 || crop < 0 || cc < 0) {
			throw new BadPageException("cost < 0");
		}
		return new CompleteResourceData(lumber, clay, iron, crop, cc);
	}

	public Type getType() throws IOException, HttpException, AuthenticationException, BadPageException {
		String pgsrc = getBuildingPage();
		String stype = findNoThrow(pgsrc, "\\Q<h1><b>\\E([^ ]+)\\Q " + user.getString("level")+ 
			" \\E\\d+\\Q</b></h1>\\E");
		if (stype == null) {
			// throw bad page exception if no this string
			if (!pgsrc.contains(user.getString("Construct new building"))) {
				throw new BadPageException("no type nor 'Construct new building'");
			}
			return Type.BUILDING_SITE;
		}
		return Type.forName(stype, user);
	}

	public void upgrade() throws IOException, HttpException, AuthenticationException, BadPageException, CannotWorkException {
		int myid = getId();
		String pgsrc = getBuildingPage(myid);
		logger.info("upgrade building: /build.php?id=" + myid);
		logger.fine("source:");
		logger.fine(pgsrc);
		// (Waiting loop)?
		String visit = findNoThrow(pgsrc, "\\Q<a href=\"\\E(\\Qdorf\\E[12]\\Q.php?a=" + myid + "&c=\\E\\p{XDigit}*)\\Q\">\\E.*?\\Q</a>\\E");
		if (visit != null) {
			logger.info("got " + visit + " as upgrade building link");
			village.httpGet(visit);
		} else {
			if (pgsrc.contains(user.getString("Construct new building"))) {
				throw new CannotWorkException("this is a building site");
			}
			String msg = find(pgsrc, "\\Q<span class=\"c\">\\E(.*?)\\Q</span>\\E");
			logger.info("got " + msg + " as cannot upgrade exception message");
			throw new CannotWorkException(msg);
		}
	}

	/**
	 * a simple way to get "/build.php?id=" + getId()
	 * @return page source of "/build.php?id=" + getId()
	 */
	protected String getBuildingPage() throws IOException, HttpException, AuthenticationException, BadPageException {
		return getBuildingPage(getId());
	}
	
	private String getBuildingPage(int useid) throws IOException, HttpException, AuthenticationException, BadPageException {
		return village.httpGet("/build.php?id=" + useid);
	}
}
